#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <sys/time.h>
#include <unistd.h>
#include <stdbool.h>
#include <fcntl.h>
#include <termios.h>
#include <poll.h>
#include "optimizer.h"

// 每次产生的魔方求解步骤的数量
#define TOTEL_SOLUTION    50
// 运行twophase库的时间
#define TWOPHASE_RUNTIME  25
// 每行串口调试信息的最大长度
#define MAX_SERIAL_LINE   512
// 串口接收缓冲区的大小
#define BUFFER_SIZE       4096

// usb_serial_jtag_driver_config_t config = {
//     .rx_buffer_size = 512,
//     .tx_buffer_size = 128
// };

// ESP32端一次能处理的数据上限
#define CHUNK_SIZE 500

static FILE *twophase_pipe = NULL;

// 串口相关函数
int open_serial_port(const char *port_name) {
    int fd = open(port_name, O_RDWR | O_NOCTTY | O_NDELAY);
    if (fd < 0) {
        perror("无法打开串口设备");
        return -1;
    }
    
    struct termios tty;
    if (tcgetattr(fd, &tty) != 0) {
        perror("获取串口属性失败");
        close(fd);
        return -1;
    }
    
    cfsetospeed(&tty, B115200);
    cfsetispeed(&tty, B115200);
    
    // 配置串口设置 (8N1)
    tty.c_cflag &= ~PARENB;
    tty.c_cflag &= ~CSTOPB;
    tty.c_cflag &= ~CSIZE;
    tty.c_cflag |= CS8;
    tty.c_cflag &= ~CRTSCTS; // 禁用硬件流控
    
    // 启用读取和忽略控制线
    tty.c_cflag |= (CLOCAL | CREAD);
    
    // 关闭软件流控
    tty.c_iflag &= ~(IXON | IXOFF | IXANY);
    
    // 原始输出模式
    tty.c_oflag &= ~OPOST;
    
    // 配置输入模式 - 非规范模式，无回显，无信号处理
    tty.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
    
    // 设置超时 - 立即返回，不阻塞
    tty.c_cc[VMIN] = 0;
    tty.c_cc[VTIME] = 0;
    
    if (tcsetattr(fd, TCSANOW, &tty) != 0) {
        perror("设置串口属性失败");
        close(fd);
        return -1;
    }
    
    // 清空输入输出缓冲区
    tcflush(fd, TCIOFLUSH);
    return fd;
}

static int solve(const char facelets[55], char *motion_sequence, int motion_sequence_len, bool verbose) {
    struct timeval start_time, end_time;
    if(verbose){
        gettimeofday(&start_time, NULL);
    }
    // 发送求解命令
    char command[64];
    snprintf(command, sizeof(command), "solve %s\n", facelets);
    fputs(command, twophase_pipe);
    fflush(twophase_pipe);

    char buffer[256];
    char twophase_solution[TOTEL_SOLUTION][128];
    int solution_steps[TOTEL_SOLUTION];
    int solution_count = 0; // 实际读取到的解法数量
    
    // 1. 等待出现包含ms的时间行
    while (1) {
        if (fgets(buffer, sizeof(buffer), twophase_pipe) == NULL) {
            return -1;
        }
        if (strstr(buffer, "ms") != NULL) {
            break; // 找到时间行，跳出循环
        }
        if (strstr(buffer, "Ready!") != NULL) {
            // 提前出现Ready!，直接返回错误
            return -1;
        }
    }

    // 2. 读取所有解法（最多TOTEL_SOLUTION个）
    while (solution_count < TOTEL_SOLUTION) {
        if (fgets(buffer, sizeof(buffer), twophase_pipe) == NULL) {
            break;
        }
        
        // 检查是否提前出现Ready!
        if (strstr(buffer, "Ready!") != NULL) {
            break; // 停止读取
        }
        
        // 移除换行符
        size_t len = strlen(buffer);
        if (len > 0 && buffer[len-1] == '\n') {
            buffer[len-1] = '\0';
        }
        
        // 分离步骤数和解法字符串
        char *step_start = strrchr(buffer, '(');
        if (step_start != NULL) {
            char *step_end = strrchr(step_start, ')');
            if (step_end != NULL) {
                *step_end = '\0';
                solution_steps[solution_count] = atoi(step_start + 1);
                *step_start = '\0';
                strncpy(twophase_solution[solution_count], buffer, 127);
                twophase_solution[solution_count][127] = '\0';
                solution_count++;
            }
        }
    }

    // 3. 等待出现Ready!（清空管道）
    while (1) {
        if (fgets(buffer, sizeof(buffer), twophase_pipe) == NULL) {
            break;
        }
        if (strstr(buffer, "Ready!") != NULL) {
            break;
        }
    }

    int best_index = -1;
    int min_total_time = INT_MAX;
    char temp_motion_sequence[1024];
    
    for (int i = 0; i < solution_count; i++) {
        int total_time = solution_to_motion("RU", twophase_solution[i], temp_motion_sequence);
        if(verbose){
            printf("[%d] %s (length=%d)\n", i, twophase_solution[i], solution_steps[i]);
            printf("机械步骤: %s (total_time=%dms)\n", temp_motion_sequence, total_time);
        }

        
        if (total_time < min_total_time) {
            min_total_time = total_time;
            best_index = i;
            strncpy(motion_sequence, temp_motion_sequence, motion_sequence_len);
            motion_sequence[motion_sequence_len - 1] = '\0';
        }
    }
    
    if (best_index >= 0) {
        if(verbose){
            printf("魔方步骤[%d]: %s\n", best_index, twophase_solution[best_index]);
        }
        motion_sequence[motion_sequence_len - 1] = '\0';
    } else {
        motion_sequence[0] = '\0';
    }
    if(verbose){
        gettimeofday(&end_time, NULL);
        double elapsed_time = (end_time.tv_sec - start_time.tv_sec) * 1000.0 +
                            (end_time.tv_usec - start_time.tv_usec) / 1000.0;
        printf("计算求解方式耗时%.2fms\n", elapsed_time);
    }
    
    return min_total_time;
}

// 计算步骤数量
static int count_steps(const char *motion_sequence) {
    int count = 0;
    const char *ptr = motion_sequence;
    
    while (*ptr) {
        while (*ptr == ' ') ptr++;
        if (*ptr) {
            count++;
            while (*ptr && *ptr != ' ') ptr++;
        }
    }
    return count;
}

// 打印时间分布统计
static void print_time_distribution(int *dist) 
{
    printf("时间长度分布统计（以100ms为区间）:\n");
    const int bucket_size = 100;
    const int bucket_count = 61;
    const int max_value = 6000;

    // 计算最大计数用于缩放柱状图
    int max_count = 0;
    for (int i = 0; i < bucket_count; i++) {
        if (dist[i] > max_count) max_count = dist[i];
    }
    if (max_count == 0) max_count = 1;  // 避免除以零
    
    // 打印每个区间的统计
    for (int i = 0; i < bucket_count; i++) {
        if (dist[i] == 0) continue;
        
        // 计算柱状图长度（最大40个字符）
        int bar_length = (dist[i] * 40 + max_count - 1) / max_count;
        
        // 打印区间标签
        if (i == bucket_count - 1 && max_value > 0) {
            printf(">=%5d: %4d [", max_value, dist[i]);
        } else {
            int start = i * bucket_size;
            int end = start + bucket_size - 1;
            printf("%4d-%4d: %4d [", start, end, dist[i]);
        }
        
        // 打印柱状图
        for (int j = 0; j < bar_length; j++) printf("#");
        for (int j = bar_length; j < 40; j++) printf(".");
        printf("]\n");
    }
}

// 打印步骤分布统计
static void print_step_distribution(int *dist, int min_steps, int max_steps) {
    printf("\n步骤数量分布统计（以1步为区间）:\n");
    
    // 计算最大计数用于缩放柱状图
    int max_count = 0;
    for (int i = min_steps; i <= max_steps; i++) {
        int bucket = (i < 100) ? i : 100;
        if (dist[bucket] > max_count) max_count = dist[bucket];
    }
    if (max_count == 0) max_count = 1;
    
    // 打印每个区间的统计
    for (int i = min_steps; i <= max_steps; i++) {
        int bucket = (i < 100) ? i : 100;
        if (dist[bucket] == 0) continue;
        
        // 计算柱状图长度
        int bar_length = (dist[bucket] * 40 + max_count - 1) / max_count;
        
        // 打印区间标签
        if (bucket == 100 && i == 100) {
            printf(">=%3d步: %4d [", 100, dist[bucket]);
        } else if (bucket == i) {
            printf("%3d步: %4d [", i, dist[bucket]);
        } else {
            continue;  // 避免重复打印
        }
        
        // 打印柱状图
        for (int j = 0; j < bar_length; j++) printf("#");
        for (int j = bar_length; j < 40; j++) printf(".");
        printf("]\n");
    }
}

static int run_solve_test(const char *testcase, bool verbose) {
    FILE *f = fopen(testcase, "r");
    char line_buffer[80];
    char motion_sequence[1024];
    int test_case_count = 0;
    
    if (f == NULL) {
        printf("无法打开 %s\n", testcase);
        return 1;
    }

    // 初始化统计变量
    int min = INT_MAX, max = 0, total_time = 0;
    int min_steps = INT_MAX, max_steps = 0, total_steps = 0;
    int time_dist[61] = {0};   // 0-5900ms (100ms间隔) + >=6000ms
    int step_dist[101] = {0};  // 0-99步 + >=100步

    while (fgets(line_buffer, sizeof(line_buffer), f)) {
        if (strlen(line_buffer) < 54) continue;
        line_buffer[54] = '\0';
        printf("\n测试用例%d: %s\n", test_case_count, line_buffer);
        
        // 测试魔方求解
        int time = solve(line_buffer, motion_sequence, sizeof(motion_sequence), verbose);
        int step_count = count_steps(motion_sequence);
        
        printf("机械步骤: %s (预估时间=%dms, 步骤数=%d)\n", 
               motion_sequence, time, step_count);
        
        // 更新时间统计
        if (time > max) max = time;
        if (time < min) min = time;
        total_time += time;
        
        // 更新步骤统计
        if (step_count > max_steps) max_steps = step_count;
        if (step_count < min_steps) min_steps = step_count;
        total_steps += step_count;
        
        // 更新时间分布
        int time_bucket = (time < 6000) ? time / 100 : 60;
        if (time_bucket >= 0 && time_bucket <= 60) time_dist[time_bucket]++;
        
        // 更新步骤分布
        int step_bucket = (step_count < 100) ? step_count : 100;
        if (step_bucket >= 0 && step_bucket <= 100) step_dist[step_bucket]++;
        
        test_case_count++;
    }
    fclose(f);

    // 打印汇总结果
    printf("\n最终结果汇总:\n");
    if (test_case_count == 0) {
        printf("未发现有效测试用例\n");
        return 0;
    }
    
    printf("测试用例数量: %d\n", test_case_count);
    printf("时间长度统计: min=%dms, max=%dms, avg=%.2fms\n",
           min, max, (float)total_time / test_case_count);
    printf("步骤数量统计: min=%d, max=%d, avg=%.2f\n\n",
           min_steps, max_steps, (float)total_steps / test_case_count);
    
    // 打印分布统计
    print_time_distribution(time_dist);
    print_step_distribution(step_dist, min_steps, max_steps);
    
    return 0;
}

static int run_daemon_mode(const char *serial_port, bool verbose) {
    int serial_fd = open_serial_port(serial_port);
    if (serial_fd < 0) {
        return -1;
    }
    
    // 发送###进入上位机模式
    write(serial_fd, "###", 3);
    tcdrain(serial_fd); 
    
    char line_buffer[MAX_SERIAL_LINE];
    char serial_buffer[BUFFER_SIZE];
    size_t buffer_pos = 0;
    
    while (1) {
        struct pollfd fds[1] = {
            {.fd = serial_fd, .events = POLLIN}
        };
        
        int ret = poll(fds, 1, 5000);  // 5秒超时
        if (ret < 0) {
            perror("poll失败");
            break;
        }
        if (fds[0].revents & (POLLERR | POLLHUP | POLLNVAL)) {
            perror("串口错误状态");
            break;
        }
        if (fds[0].revents & POLLIN) {
            ssize_t n = read(serial_fd, serial_buffer + buffer_pos, sizeof(serial_buffer) - buffer_pos);
            if (n <= 0) {
                if (n < 0) perror("串口读取失败");
                continue;
            }
            
            buffer_pos += n;
            
            // 处理完整行
            size_t line_start = 0;
            for (size_t i = 0; i < buffer_pos; i++) {
                if (serial_buffer[i] == '\n') {
                    size_t line_len = i - line_start;
                    memcpy(line_buffer, serial_buffer + line_start, line_len);
                    line_buffer[line_len] = '\0';
                    
                    // 输出到stdout
                    printf("%s\n", line_buffer);
                    
                    // 处理请求
                    char *request_start = strstr(line_buffer, "run_solve = ");
                    if (request_start != NULL) {
                        request_start += 12; // 跳过"run_solve = "
                        if (strlen(request_start) >= 54) {
                            char facelets[55];
                            strncpy(facelets, request_start, 54);
                            facelets[54] = '\0';
                            
                            char motion_sequence[1024];
                            int total_time = solve(facelets, motion_sequence, sizeof(motion_sequence), verbose);
                            
                            char response[2048];
                            snprintf(response, sizeof(response), "#%s(%d)", motion_sequence, total_time);
                            const char *full_response = response;
                            size_t total_length = strlen(response);
                            size_t sent = 0;
                            printf("向ESP32发送数据: %s (长度:%zu)\n", full_response, total_length);

                            // 分段发送（通常只需要一段就能完成发送）
                            while (sent < total_length) {
                                size_t chunk_size = (total_length - sent) > CHUNK_SIZE 
                                                ? CHUNK_SIZE 
                                                : (total_length - sent);
                                
                                // 发送当前段数据
                                ssize_t n = write(serial_fd, full_response + sent, chunk_size);
                                tcdrain(serial_fd); 
                                sent += n;
                                
                                // 添加10ms延时让ESP32处理缓冲区（通常不会出现500字节还不够的情况, 这个延时不会影响性能）
                                usleep(10000);
                                // printf("发送段 %zu-%zu/%zu\n", sent - n, sent, total_length);
                            }
                        }
                    }
                    
                    line_start = i + 1;
                }
            }
            
            if (line_start > 0) {
                // 移动剩余数据
                memmove(serial_buffer, serial_buffer + line_start, buffer_pos - line_start);
                buffer_pos -= line_start;
            }
        }
    }
    
    close(serial_fd);
    return 0;
}

int main(int argc, char *argv[]) {
    bool verbose = false;
    if (argc >= 3 && strcmp(argv[1], "-s") == 0) {
        // 处理直接求解模式
    } else if (argc >= 3 && strcmp(argv[1], "-t") == 0) {
        // 处理测试模式
    } else if (argc >= 3 && strcmp(argv[1], "-d") == 0) {
        // 处理后台服务模式
    } else {
        printf("使用说明:\n");
        printf("-s: 输入魔方状态字符串，输出解法:\n");
        printf("    示例：%s -s BBBFULRUBUURFRRRDFDFLUFDLRUUUFFDRLDLRRFLLBBLFDLUBBDDBD\n", argv[0]);
        printf("-t: 读取大量测试用例，批量测试魔方求解算法:\n");
        printf("    示例：%s -t log/testcase.txt\n", argv[0]);
        printf("-d: 开启后台服务，作为魔方机器人解算上位机使用\n");
        printf("    示例：%s -d /dev/ttyACM0\n", argv[0]);
        printf("-v: 输出更多的调试信息，与以上三者中的任意参数组合使用，必须位于命令行末尾\n");
        printf("    示例：%s -s BBBFULRUBUURFRRRDFDFLUFDLRUUUFFDRLDLRRFLLBBLFDLUBBDDBD -v\n", argv[0]);
        return 0;
    }
    if (argc >= 4 && strcmp(argv[3], "-v") == 0) {
        // 详细模式
        verbose = true;
    }
    // 获取逻辑核心数(包括超线程)
    long logical_cores = sysconf(_SC_NPROCESSORS_ONLN);
    if (logical_cores < 1) logical_cores = 1;
    
    // 设置线程数
    int threads = (int)logical_cores;
    
    // 设置分割数
    int splits = (threads + 5) / 6;
    if (splits < 1) splits = 1;
    
    // 动态构建命令字符串
    char cmd_line[128];
    snprintf(cmd_line, sizeof(cmd_line), 
             "./twophase -m %d -n %d -t %d -s %d", 
             TWOPHASE_RUNTIME, TOTEL_SOLUTION, threads, splits);
    
    printf("检测到逻辑核心: %ld\n", logical_cores);
    printf("优化设置: -t %d (线程数), -s %d (分割数), 比例: %.2f\n", 
           threads, splits, (double)threads / splits);
    
    // 启动twophase
    twophase_pipe = popen(cmd_line, "r+");
    if (twophase_pipe == NULL) {
        perror("启动twophase失败");
        return 1;
    }

    char buffer[128];
    printf("等待twophase准备就绪...\n");
    while (fgets(buffer, sizeof(buffer), twophase_pipe) != NULL) {
        if(verbose){
            printf("%s", buffer);
        }
        if (strstr(buffer, "Ready!")) {
            break;
        }
    }
    
    // 处理不同模式
    if (argc >= 2 && strcmp(argv[1], "-s") == 0 && argc >= 3) {
        char motion_sequence[1024];
        int len = solve(argv[2], motion_sequence, sizeof(motion_sequence), verbose);
        printf("机械步骤: %s\n", motion_sequence);
        printf("预估时间: %dms\n", len);
    } else if (argc >= 3 && strcmp(argv[1], "-t") == 0) {
        run_solve_test(argv[2], verbose);
    } else if (argc >= 3 && strcmp(argv[1], "-d") == 0) {
        run_daemon_mode(argv[2], verbose);
    } else {
        fprintf(stderr, "错误：无效参数或参数不足\n");
    }
    
    pclose(twophase_pipe);
    return 0;
}
